package cn.lbd.auth.utils;

import cn.lbd.auth.core.Common;
import cn.lbd.auth.security.GrantedAuthorityImpl;
import cn.lbd.auth.security.JwtAuthenticatioToken;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * JWT工具类
 * @author fangliqng
 * @date 2020.12.5
 */
public class JwtTokenUtils implements Serializable {

	private static final long serialVersionUID = 1L;
	
	/**
	 * 用户名称
	 */
	private static final String USERNAME = Claims.SUBJECT;
	/**
	 * 创建时间
	 */
	private static final String CREATED = "created";
	/**
	 * 权限列表
	 */
	private static final String AUTHORITIES = "authorities";
	/**
     * 密钥
     */
    private static final String SECRET = "abcdefgh";
    /**
     * 有效期4小时
     */
    /*private static final long EXPIRE_TIME = 4 * 60 * 60 * 1000;*/
	private static final long EXPIRE_TIME = 2 * 60 * 1000;
    /**
	 * 生成令牌
	 *
	 * @param
	 * @return 令牌
	 */
	public static String generateToken(Authentication authentication) {
	    Map<String, Object> claims = new HashMap<>(3);
	    claims.put(USERNAME, SecurityUtils.getUsername(authentication));
	    claims.put(CREATED, new Date());
	    claims.put(AUTHORITIES, authentication.getAuthorities());
	    return generateToken(claims);
	}

	/**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private static String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        return Jwts.builder()
				.setClaims(claims)
				.setExpiration(expirationDate)
				.signWith(SignatureAlgorithm.HS512, SECRET)
				.compact();
    }

    /**
	 * 从令牌中获取用户名
	 *
	 * @param token 令牌
	 * @return 用户名
	 */
	public static String getUsernameFromToken(String token) {
	    String username;
	    try {
	        Claims claims = getClaimsFromToken(token);
	        username = claims.getSubject();
	    } catch (Exception e) {
	        username = null;
	    }
	    return username;
	}
	
	/**
	 * 根据请求令牌获取登录认证信息
	 * @param
	 * @return 用户名
	 */
	public static Authentication getAuthenticationeFromToken(HttpServletRequest request) {
		Authentication authentication = null;
		// 获取请求携带的令牌
		String token = JwtTokenUtils.getToken(request);
		// 请求令牌不能为空
		if(token != null) {
			// 上下文中Authentication为空
			if(SecurityUtils.getAuthentication() == null) {
				Claims claims = getClaimsFromToken(token);
				if(claims == null) {
					return null;
				}
				String username = claims.getSubject();

				if(username == null) {
					return null;
				}
				if(isTokenExpired(token)) {
					return null;
				}
				Object authors = claims.get(AUTHORITIES);
				List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
				if (authors != null && authors instanceof List) {
					for (Object object : (List) authors) {
						authorities.add(new GrantedAuthorityImpl((String) ((Map) object).get("authority")));
					}
				}
				authentication = new JwtAuthenticatioToken(username, null, authorities, token);
			} else {
				if(validateToken(token, SecurityUtils.getUsername())) {
					// 如果上下文中Authentication非空，且请求令牌合法，直接返回当前登录认证信息
					authentication = SecurityUtils.getAuthentication();
				}
			}
		}
		return authentication;
	}

	/**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    /**
	 * 验证令牌
	 * @param token
	 * @param username
	 * @return
	 */
	public static Boolean validateToken(String token, String username) {
	    String userName = getUsernameFromToken(token);
	    return (userName.equals(username) && !isTokenExpired(token));
	}

	/**
	 * 刷新令牌
	 * @param token
	 * @return
	 */
	public static String refreshToken(String token) {
	    String refreshedToken;
	    try {
	        Claims claims = getClaimsFromToken(token);
	        claims.put(CREATED, new Date());
	        refreshedToken = generateToken(claims);
	    } catch (Exception e) {
	        refreshedToken = null;
	    }
	    return refreshedToken;
	}

	/**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public static Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取请求token
     * @param request
     * @return
     */
    public static String getToken(HttpServletRequest request) {
    	String token = request.getHeader("Authorization");
        String tokenHead = "Bearer ";
        if(token == null) {
        	token = request.getHeader("token");
        } else if(token.contains(tokenHead)){
        	token = token.substring(tokenHead.length());
        } 
        if("".equals(token)) {
        	token = null;
        }
        return token;
    }

	public static void main(String[] args) {
		System.out.println(getClaimsFromToken("eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxMDAwMDAwMCIsImV4cCI6MTYxMDEzMTM1MCwiY3JlYXRlZCI6MTYxMDA4ODE1MDc4NCwiYXV0aG9yaXRpZXMiOlt7ImF1dGhvcml0eSI6IjExMTAwMTI1In0seyJhdXRob3JpdHkiOiIxMDAwMDAwMSJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMTcifSx7ImF1dGhvcml0eSI6IjExMDAwMDM5In0seyJhdXRob3JpdHkiOiIxMzEwMDAwNiJ9LHsiYXV0aG9yaXR5IjoiMTAwMDAwMDIifSx7ImF1dGhvcml0eSI6IjExMDAwMDE1In0seyJhdXRob3JpdHkiOiIxMTAwMDAzNyJ9LHsiYXV0aG9yaXR5IjoiMTMxMDAwMDQifSx7ImF1dGhvcml0eSI6IjEwMDAwMDA0In0seyJhdXRob3JpdHkiOiIxMTAwMDAxNiJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMzgifSx7ImF1dGhvcml0eSI6IjEzMTAwMDAzIn0seyJhdXRob3JpdHkiOiIxMDAwMDAwNSJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMzUifSx7ImF1dGhvcml0eSI6IjEzMTAwMDAyIn0seyJhdXRob3JpdHkiOiIxMDAwMDAwNiJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMTQifSx7ImF1dGhvcml0eSI6IjExMDAwMDM2In0seyJhdXRob3JpdHkiOiIxMTAwMDAxMSJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMzMifSx7ImF1dGhvcml0eSI6IjExMDAwMDM0In0seyJhdXRob3JpdHkiOiIxMTAwMDAyMCJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMjEifSx7ImF1dGhvcml0eSI6IjEwMDAwMDUxIn0seyJhdXRob3JpdHkiOiIxMDAwMDA1MiJ9LHsiYXV0aG9yaXR5IjoiMTIwMDAwMDAifSx7ImF1dGhvcml0eSI6IjEyMDAwMDAxIn0seyJhdXRob3JpdHkiOiIxMTAwMDAwOCJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMDkifSx7ImF1dGhvcml0eSI6IjExMDAwMDI4In0seyJhdXRob3JpdHkiOiIxMTAwMDAwNyJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMjkifSx7ImF1dGhvcml0eSI6IjExMDAwMDI2In0seyJhdXRob3JpdHkiOiIxMTAwMDAyNyJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMjQifSx7ImF1dGhvcml0eSI6IjExMDAwMDI1In0seyJhdXRob3JpdHkiOiIxMTAwMDAyMiJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwNDQifSx7ImF1dGhvcml0eSI6IjExMDAwMDIzIn0seyJhdXRob3JpdHkiOiIxMTAwMDAzMSJ9LHsiYXV0aG9yaXR5IjoiMTEwMDAwMzIifSx7ImF1dGhvcml0eSI6IjExMDAwMDMwIn0seyJhdXRob3JpdHkiOiIxMjAwMDAxMSJ9LHsiYXV0aG9yaXR5IjoiMTMwMDAwMDEifV19.1LBVK-uEbnVjRLLzvFNjlKG0RDf6wy6Z8Fe6sdC6mmkbNyYzj6T1QBKZMrjuNiq6Ed7JfEvDr8FuWCHHZyPtEg"));
	}
}